Flattening and Unflattening Shapes
In order to save a QuickDraw GX shape (shape object plus its referenced objects) to external storage, transmit it across a network, or save it to the Clipboard, you must convert it into an equivalent flattened, rather than object-based, description. The flattened information is a compressed and stream-based description with a public
format so that applications can share the data and reconstruct the objects.You can use the
GXFlattenShape
function to convert any shape (even a picture shape, which contains other shapes) into its flattened form. You can then store the data, examine it, or manipulate it as you wish; the data follows the format defined in the stream format chapter of Inside Macintosh: QuickDraw GX Environment and Utilities.To reconstruct a shape's object-based description from its flattened stream, you can manually create and initialize a set of objects based on the information in the stream,
but if QuickDraw GX is available, it is far easier and more efficient to use theGXUnflattenShape
function to do it automatically.To use the flattening or unflattening functions, you first allocate a structure called a spool block. The spool block contains needed information and points to a buffer that holds the flattened data. In the spool block, you are required to provide a pointer to a callback spool function that you provide. The spool function reads the stream data into the buffer or writes it to a file from the buffer.
Listing 2-3 is a library function that flattens a shape and returns a handle to the flattened data. It uses a spool-block structure (
spool
) embedded within a library-defined structure (block
) of typeUserSpool
. The function sets up the spool-block structure, including placing into it a pointer to the spool function. It specifiesnil
for the buffer pointer and 0 for the buffer size, in which case QuickDraw GX allocates a default buffer for the task. When it callsGXFlattenShape
, the function sets two flatten flags, so that both a list of fonts and a list of all the individual glyphs used is attached to the flattened shape.Listing 2-3 Flattening a shape
Handle ShapeToHandle(gxShape source) { UserSpool block; block.spool.spoolProcedure = (long (*)(gxSpoolCommand, struct gxSpoolBlock *)) HandleSpoolProc; block.spool.buffer = nil; block.spool.bufferSize = 0; GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten, &block.spool); return block.data; }Listing 2-4 is a library function that unflattens a shape from data referenced by a handle (source
). Like Listing 2-3, it sets up a spool-block structure and places into it a pointer to the spool function. When it callsGXUnflattenShape
, the function specifies the size of the flattened data and the list of view ports to be assigned to the unflattened shape's transform object.Listing 2-4 Unflattening a shape
gxShape HandleToShape(Handle source, long count, const gxViewPort portList[]) { UserSpool block; block.spool.spoolProcedure = (long (*)(gxSpoolCommand, struct gxSpoolBlock *)) HandleSpoolProc; block.spool.buffer = nil; block.spool.bufferSize = 0; block.data = source; return GXUnflattenShape(&block.spool, count, portList); }Your flattening/unflattening spool function responds to five commands from QuickDraw GX (described on page 2-92). In most cases it simply reads or writes a buffer of data at a time during the flattening or unflattening operation, and then closes up when the operation is finished. However, for special purposes you can write a spool function that parses the stream of data by reading information in the spool block and manipulating the size of the buffer that QuickDraw GX can read from or write into.Listing 2-5 is a partial listing that shows the overall structure of a typical spool function for flattening and unflattening. This function, however, parses the stream as it is being flattened or unflattened. In the case of writing (flattening), the listing shows that the function sets the buffer size to equal the current operation size so that no more than a single operation can be flattened at once. Therefore, each time it is called, the spool file can read the fields of the spool block to determine the kind of information the current operation consists of and decide how large to make the buffer for the next write.
Listing 2-5 A spool function that parses shape data
static long MyParseSpoolProc(spoolCommand command, gxSpoolBlock *block) { switch (command) { case openReadSpool: . . /* spool function prepares for unflattening */ . break; case openWriteSpool: . . /* spool function prepares for flattening */ . break; case closeSpool: . . /* spool function closes up when finished */ . break; case readSpool: . . /* spool function parses and reads for unflattening */ . break; case writeSpool: /* see if current operation < 32K (real buffer size) */ if (block->spool.operationSize < 32768) /* set buffer size to operation size */ block->spool.bufferSize = block->spool.operationSize; else block->spool.bufferSize = 32000; /* don't overflow */ . /* . Spool function examines spool block, parses data, . writes flatttened data to disk . */ break; } }The application sets up the conditions for this spool function by first allocating a 32 KB buffer, but setting thesize
field of the spool block to 1. This causesGXFlattenShape
orGXUnflattenShape
to read only a single byte into the buffer the first time through, after which the spool function can analyze that byte and proceed with parsing. (For simple reading or writing, your application typically sets thesize
field to the actual size of the buffer--32 KB in this case--and the spool function does not parse the stream at all).The
GXFlattenShape
function is described on page 2-88. TheGXUnflattenShape
function is described on page 2-90. The spool block structure is described on page 2-49. The application-defined spool function is described on page 2-91. The flatten flags are described on page 2-48.